package boot

import (
	"fmt"
	"gino/global"
	"gino/pkg/glog"
	"gorm.io/driver/mysql"
	_ "gorm.io/driver/mysql"
	"gorm.io/gorm"
	gormLogger "gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
	"log"
	"os"
	"time"
)

func Mysql() {
	var err error
	mysqlCfg := global.Config.Mysql

	// 日志配置
	logger := gormLogger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
		gormLogger.Config{
			SlowThreshold: time.Second,     // 慢 SQL 阈值
			LogLevel:      gormLogger.Info, // Log level
			Colorful:      false,           // 禁用彩色打印
		},
	)

	// 切换Zap日志记录器
	if global.Config.Mysql.ZapLogger {
		logger = NewGormZapLogger(glog.Logger)
	}

	// 数据库配置
	// "user:password@/dbname?charset=charset=utf8mb4&parseTime=True&loc=Local"
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		mysqlCfg.User,
		mysqlCfg.Password,
		mysqlCfg.Host,
		mysqlCfg.Port,
		mysqlCfg.Name,
	)

	// 数据库初始化
	global.DB, err = gorm.Open(mysql.New(mysql.Config{
		DSN:                       dsn,   // DSN data source name
		DefaultStringSize:         256,   // string 类型字段的默认长度
		DisableDatetimePrecision:  true,  // 禁用 datetime 精度，MySQL 5.6 之前的数据库不支持
		DontSupportRenameIndex:    true,  // 重命名索引时采用删除并新建的方式，MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
		DontSupportRenameColumn:   true,  // 用 `change` 重命名列，MySQL 8 之前的数据库和 MariaDB 不支持重命名列
		SkipInitializeWithVersion: false, // 根据版本自动配置
	}), &gorm.Config{
		// 表、列命名策略
		NamingStrategy: schema.NamingStrategy{
			TablePrefix:   global.Config.Mysql.TablePrefix,
			SingularTable: true,
		},
		// Logger
		Logger: logger,
	})

	if err != nil {
		log.Fatal("Database connection failed " + err.Error())
	}

	mysqlDB, err := global.DB.DB()
	if err != nil {
		panic(err)
	}

	// 设置空闲模式中的最大连接数 <=0，则不保留空闲连接
	mysqlDB.SetMaxIdleConns(mysqlCfg.MaxIdleConn)

	// 设置与数据库的最大打开连接数 0表示无限制
	mysqlDB.SetMaxOpenConns(mysqlCfg.MaxOpenConn)

	// 设置连接最长时间 d <= 0，连接不会关闭。
	mysqlDB.SetConnMaxLifetime(time.Duration(global.Config.Mysql.MaxLifeTime) * time.Second)

	// 设置连接空闲状态的最长时间 <= 0，连接不会因为连接的空闲时间而关闭。
	mysqlDB.SetConnMaxIdleTime(time.Duration(global.Config.Mysql.MaxLifeTime) * time.Second)
}
